

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Calendar;
import java.util.GregorianCalendar;

import aufgabe1.Course;
import aufgabe1.CourseException;
import aufgabe1.CourseManager;
import aufgabe1.Student;

/**
 * performs test cases to confirm the correct implementation
 * @author Lukas Koell
 * @author David Medenjak
 * @author Johannes Riedmann
 */
public class Test {
	/** number of test done */
	static int testCounter = 0;
	/** number of successful tests done */
	static int successCounter = 0;

	/**
	 * @param args the command line arguments
	 */
	public static void main(String[] args) throws Exception {
		doTest(testCanCreateCourse(), "Can create course");

		doTest(testStudentListing(), "Can list students");

		doTest(testCanListCourses(), "Can list courses");

		doTest(testCanSubscribeStudentToCourse(), "Can subscribe student to course");

		doTest(testNoDoubleSubscriptionsPossible(), "No student can subscribe twice to the same course");

		doTest(testSubscriptionOnlyPossibleDuringValidDates(), "Students can only subscribe during valid dates");
		
		doTest(testStudentCanUnsubscribe(), "Students can unsubscribe");
		
		doTest(testStudentCanOnlyUnsubscribeDuringValidPeriod(), "Students can only unsubscribe during valid dates");

		doTest(testPersistentStore(), "Persistent store working");

		System.out.println("\n" + successCounter + " out of " + testCounter + " tests succeeded.");
	}

	/**
	 * shows which tests succeeded and which failed and performs output
	 * @param method shows if test succeeded of failed
	 * @param name is a short description of the testcase
	 */
	private static void doTest(boolean method, String name) {
		System.out.print(name);
		if (method == true) {
			successCounter++;
			System.out.println(" ... succeeded.");
		} else {
			System.out.println(" ... failed.");
		}
		testCounter++;
	}

	/**
	 * Test if a new course can be created
	 */
	private static boolean testCanCreateCourse() {
		try {
			createDummyCourse();
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * Test if we can list all courses
	 */
	private static boolean testCanListCourses() {
		CourseManager cm = new CourseManager();
		cm.addCourse(createDummyCourse());
		cm.addCourse(createDummyCourse());

		String totalString = cm.listCourses();
		
		String comparison = "Nr.\tTitel\t\tfr. Anmeldetermin\tsp. Anmeldetermin\tsp. Abmeldetermin\tangemeldet\n"
			+ "1234\tOOP\t\tSat Jan 01 00:00:00 CET 2000\tMon Jan 10 00:00:00 CET 2000\tTue Jan 25 00:00:00 CET 2000\t0\n"
			+ "1234\tOOP\t\tSat Jan 01 00:00:00 CET 2000\tMon Jan 10 00:00:00 CET 2000\tTue Jan 25 00:00:00 CET 2000\t0\n";
		if(comparison.equals(totalString)){
			return true;
		}
		return false;
	}

	/**
	 * Test if a student can be added to a course
	 */
	private static boolean testCanSubscribeStudentToCourse() {
		Course oop = createDummyCourse();
		Student zack = new Student(1234567, "Zack Brannigan");
		try {
			oop.subscribeStudent(zack, new GregorianCalendar(2000, Calendar.JANUARY, 4));
			return true;
		} catch(Exception e){
			return false;
		}
	}

	/**
	 * Test that no student can subscribe twice
	 */
	private static boolean testNoDoubleSubscriptionsPossible() {
		Course oop = createDummyCourse();
		Student zack = new Student(1234567, "Zack Brannigan");
		// test passes if the CourseException is thrown
		try {
			oop.subscribeStudent(zack, new GregorianCalendar(2000, Calendar.JANUARY, 5));
			oop.subscribeStudent(zack, new GregorianCalendar(2000, Calendar.JANUARY, 6));
			return false;
		} catch (CourseException e) {
			return true;
		}
	}

	/**
	 * Test if student can only subscribe within possible dates
	 */
	private static boolean testSubscriptionOnlyPossibleDuringValidDates() {
		Course oop = createDummyCourse();
		Student zack = new Student(1234567, "Zack Brannigan");
		
		// test passes when exception is thrown
		try {
			// too early
			oop.subscribeStudent(zack, new GregorianCalendar(1999, Calendar.JANUARY, 20));
			// too late
			oop.subscribeStudent(zack, new GregorianCalendar(2001, Calendar.JANUARY, 5));
			return false;
		} catch (CourseException e) {
			return true;
		}
	}

	/**
	 * Test if Student can unsubscribe
	 */
	private static boolean testStudentCanUnsubscribe() {
		Course oop = createDummyCourse();
		Student zack = new Student(1234567, "Zack Brannigan");
		
		try {
			oop.subscribeStudent(zack, new GregorianCalendar(2000, Calendar.JANUARY, 5));
			oop.unsubscribeStudent(zack, new GregorianCalendar(2000, Calendar.JANUARY, 20));
			
			if(oop.numberOfSubscribedStudents() == 0){
				return true;
			}
			return false;
		} catch (CourseException e) {
			return false;
		}
	}

	/**
	 * Test if Student can only unsubscribe during valid period
	 */
	private static boolean testStudentCanOnlyUnsubscribeDuringValidPeriod() {
		Course oop = createDummyCourse();
		Student zack = new Student(1234567, "Zack Brannigan");
		
		try {
			oop.subscribeStudent(zack, new GregorianCalendar(2000, Calendar.JANUARY, 5));
			oop.unsubscribeStudent(zack, new GregorianCalendar(2000, Calendar.JANUARY, 27));
			return false;
		} catch (CourseException e) {
			if(oop.numberOfSubscribedStudents() == 1){
				return true;
			}
			return false;
		}
	}

	/**
	 * Test if listing of all course students works
	 */
	private static boolean testStudentListing() throws CourseException {
		Course myCourse = new Course(1234, "OOP", new GregorianCalendar(2000, Calendar.JANUARY, 1), new GregorianCalendar(2000, Calendar.JANUARY, 10), 
				new GregorianCalendar(2000, Calendar.JANUARY, 25));

		Student testStudent = new Student(1234566, "Lukas Koell");

		try {
			myCourse.subscribeStudent(null, null);
		} catch (CourseException e) {
		}
		myCourse.subscribeStudent(testStudent, new GregorianCalendar(2000, Calendar.JANUARY, 5));

		if (myCourse.listStudents().equals("1234566: Lukas Koell\n")) {
			return true;
		}
		return false;
	}
	
	/**
	 * creates a dummy-Course-object, which is used to perform testcases
	 */
	private static Course createDummyCourse(){
		return new Course(1234, "OOP", new GregorianCalendar(2000, Calendar.JANUARY, 1), new GregorianCalendar(2000, Calendar.JANUARY, 10), 
				new GregorianCalendar(2000, Calendar.JANUARY, 25));
	}
	
	private static boolean testPersistentStore(){
		CourseManager cm = new CourseManager();
		cm.addCourse(createDummyCourse());
		cm.addCourse(createDummyCourse());

		
		// Write to disk with FileOutputStream
		FileOutputStream f_out;
		try {
			f_out = new FileOutputStream("coursemanager.data");
			
			ObjectOutputStream obj_out;
			try {
				obj_out = new ObjectOutputStream (f_out);
				// Write object out to disk
				obj_out.writeObject ( cm );
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return false;
		}
		return true;

	}
}
